#include "playscene.h"
#include<QDebug>
#include<QMenu>
#include<QMenuBar>
#include<QPainter>
#include"mypushbutton.h"
#include<QTimer>
#include<QLabel>
#include"mygrid.h"
#include"dataconfig.h"
#include"QPropertyAnimation"
#include<QSound>
#include"choice.h"
#include<bits/stdc++.h>
#include<QEventLoop>
class Solution {
public://全局变量还不给过
    PlayScene *play;
    QTimer timer;
    Solution(PlayScene *play){
        this->play=play;
    }
int row[9][9],col[9][9],cell[3][3][9];//row[3][6]=1表示第4行填过6，cell[1][2][8]=1表示地2行3列大格子中填过9
    bool flag=0;
    void dfs(std::vector<std::vector<char>>& board,int r,int c,PlayScene *play){
        if(play->indfsWantquit)return;
        if(c>8)r++,c=0;//这个本质上是折叠了区间的全排列，八皇后就是全排列，这个相当于转弯操作
        if(r>8){
            flag=1;
            return ;//终点不长
        }
        if(board[r][c]!='.')dfs(board,r,c+1,play);
        else {
            for(int i=0;i<=8;i++){//各个方向（颜色）
                if(row[r][i]==0&&col[c][i]==0&&cell[r/3][c/3][i]==0){//能否长草，能长就长
                    play->gridBtn[r][c]->stopFlag(i+1);
                    //QSound *startsound=new QSound(":/res/TapButtonSound.wav");//开始按钮音效
                    //startsound->play();//点击发声
                    QEventLoop eventloop;
                        QTimer::singleShot(10, &eventloop, SLOT(quit()));
                        eventloop.exec();
                    board[r][c]=i+'0'+1,row[r][i]=1,col[c][i]=1,cell[r/3][c/3][i]=1;//i=1表示数字1，所以忘了+1
                    dfs(board,r,c+1,play);//长了还长
                    if(flag==0)board[r][c]='.',row[r][i]=0,col[c][i]=0,cell[r/3][c/3][i]=0;//如果没有成功需要除草，否则不需要
                    else return;
                }
            }
        }
    }
    std::vector<std::vector<char>> solveSudoku(std::vector<std::vector<char>>& board) {
        memset(row,0,sizeof row),memset(col,0,sizeof col),memset(cell,0,sizeof cell);
        for(int r=0;r<=8;r++){
            for(int c=0;c<=8;c++){
                if(board[r][c]!='.'){
                    int num=board[r][c]-'0';
                    row[r][num-1]=1,col[c][num-1]=1,cell[r/3][c/3][num-1]=1;//张冠李戴
                }
            }
        }
        timer.start(30);
        play->isIndfs=true;
        dfs(board,0,0,play);
        play->isIndfs=false;
        play->isWin=true;
        play->putAnum();
        return board;
    }
};

PlayScene::PlayScene(int levelNum)
{
    QSound *backSound=new QSound(":/res/BackButtonSound.wav");
    QSound*flipSound=new QSound(":/res/CoinFlipSound.wav");
    //QSound*winSound=new QSound(":/res/LevelWinSound.wav");//好像音效有问题
    //先加上音效
    QString str=QString("进入了 %1关").arg(levelNum);
    qDebug()<<str;
    this->levelIndex=levelNum;
    //设置大小
    this->setFixedSize(800,800);
    //设置图标
    this->setWindowIcon(QPixmap(":/res/sodukuIcon2.jpg"));
    //设置标题
    this->setWindowTitle("数独");

    //显示操作界面
    Choice *choice =new Choice(this);
    this->mychoice=choice;
    choice->show();
    choice->move(550,0);
    choice->setGeometry(this->x()+550,this->y()+280,choice->width(),choice->height());
    //操作界面退出事件
//    connect(choice,&Choice::buttonclick1,[&](){
//        //这里的格式必须像 QPushButton::clicked
//        qDebug()<<"choice,&Choice::buttonclick1";
//        if(this->spinexist)
//        this->gridBtn[spingridx][spingridy]->stopFlag();
//        spinexist=false;//没有旋转的了
//    });//close确实是信号,但是这里就是有问题
    //必须要有spin并且可以选才可以
    connect(choice,&Choice::buttonclickd,[&](){
        qDebug()<<"spinexist"<<spinexist<<"spingridx"<<spingridx<<"spingridy"<<spingridy;
    });
    connect(choice,&Choice::buttonclick1,[&](){if(this->spinexist&&row[spingridx][0]==0&&col[spingridy][0]==0&&cell[spingridx/3][spingridy/3][0]==0)
            this->spingridBecome=1,this->putAnum();else {
            QMessageBox::information(this,QString("不对哦"),QString("再看看"));
        }});
    connect(choice,&Choice::buttonclick2,[&](){if(this->spinexist&&row[spingridx][1]==0&&col[spingridy][1]==0&&cell[spingridx/3][spingridy/3][1]==0)
            this->spingridBecome=2,this->putAnum();else {
            QMessageBox::information(this,QString("不对哦"),QString("再看看"));
        }});
    connect(choice,&Choice::buttonclick3,[&](){if(this->spinexist&&row[spingridx][2]==0&&col[spingridy][2]==0&&cell[spingridx/3][spingridy/3][2]==0)
            this->spingridBecome=3,this->putAnum();else {
            QMessageBox::information(this,QString("不对哦"),QString("再看看"));
        }});
    connect(choice,&Choice::buttonclick4,[&](){if(this->spinexist&&row[spingridx][3]==0&&col[spingridy][3]==0&&cell[spingridx/3][spingridy/3][3]==0)
            this->spingridBecome=4,this->putAnum();else {
            QMessageBox::information(this,QString("不对哦"),QString("再看看"));
        }});
    connect(choice,&Choice::buttonclick5,[&](){if(this->spinexist&&row[spingridx][4]==0&&col[spingridy][4]==0&&cell[spingridx/3][spingridy/3][4]==0)
            this->spingridBecome=5,this->putAnum();else {
            QMessageBox::information(this,QString("不对哦"),QString("再看看"));
        }});
    connect(choice,&Choice::buttonclick6,[&](){if(this->spinexist&&row[spingridx][5]==0&&col[spingridy][5]==0&&cell[spingridx/3][spingridy/3][5]==0)
            this->spingridBecome=6,this->putAnum();else {
            QMessageBox::information(this,QString("不对哦"),QString("再看看"));
        }});
    connect(choice,&Choice::buttonclick7,[&](){if(this->spinexist&&row[spingridx][6]==0&&col[spingridy][6]==0&&cell[spingridx/3][spingridy/3][6]==0)
            this->spingridBecome=7,this->putAnum();else {
            QMessageBox::information(this,QString("不对哦"),QString("再看看"));
        }});
    connect(choice,&Choice::buttonclick8,[&](){if(this->spinexist&&row[spingridx][7]==0&&col[spingridy][7]==0&&cell[spingridx/3][spingridy/3][7]==0)
            this->spingridBecome=8,this->putAnum();else {
            QMessageBox::information(this,QString("不对哦"),QString("再看看"));
        }});
    connect(choice,&Choice::buttonclick9,[&](){if(this->spinexist&&row[spingridx][8]==0&&col[spingridy][8]==0&&cell[spingridx/3][spingridy/3][8]==0)
            this->spingridBecome=9,this->putAnum();else {
            QMessageBox::information(this,QString("不对哦"),QString("再看看"));
        }});

    //判断是否胜利
    connect(this,&PlayScene::putAnum,[=](){
        if(isWin){//坑爹，这里硬币变成9对应的应该是row[r][8]=1
            flipSound->play();//好像音效有问题
            qDebug()<<"ISWIn";
            QLabel*winlabel=new QLabel;
            QPixmap tmppix;
            bool suc=tmppix.load(":/res/sodukuIcon.jpg");
            if(suc)qDebug()<<"success show 胜利图片";
            winlabel->setPixmap(tmppix),winlabel->setParent(this),winlabel->setGeometry(0,0,tmppix.width(),0.6*tmppix.height()),winlabel->move(this->width()*0.5-tmppix.width()*0.5,-50),winlabel->hide(), winlabel->show();
            QPropertyAnimation *animation=new QPropertyAnimation(winlabel,"geometry");
            animation->setDuration(1000),animation->setStartValue(QRect(winlabel->x(),winlabel->y(),winlabel->width(),winlabel->height())),animation->setEndValue(QRect(winlabel->x(),winlabel->y()+114,winlabel->width(),winlabel->height())), animation->setEasingCurve(QEasingCurve::OutBounce),animation->start();
            return;
        }
        if(SpinGridNum!=-1)return;//如果想要改之前写的值，只能撤销不能修改
       //每次点击choice的123456789并且this->spinexist都会触发
       this->gridBtn[spingridx][spingridy]->stopFlag(spingridBecome);//让数字显示
       spinexist=false;//停止转动，允许继续点击
       int r=spingridx,c=spingridy;
       cnt++;
       qDebug()<<"r   "<<r<<"c    "<<c<<"cnt   "<<cnt;//显示一下哪里在旋转，和已经有填了多少了
       row[r][spingridBecome-1]=1,col[c][spingridBecome-1]=1,cell[r/3][c/3][spingridBecome-1]=1;//记录结果
       if(cnt>=81)isWin=true;
       if(isWin){//坑爹，这里硬币变成9对应的应该是row[r][8]=1
           flipSound->play();//好像音效有问题
           qDebug()<<"ISWIn";
           //不能再操作了
//           for(int i=0;i<9;i++){
//               for(int j=0;j<9;j++){
//                   gridBtn[i][j]->iswin=true;
//               }
//           }
           //胜利图片显示
           QLabel*winlabel=new QLabel;
           QPixmap tmppix;
           bool suc=tmppix.load(":/res/sodukuIcon.jpg");
           if(suc)qDebug()<<"success show 胜利图片";
           winlabel->setPixmap(tmppix);
           winlabel->setParent(this);
           winlabel->setGeometry(0,0,tmppix.width(),0.6*tmppix.height());
           winlabel->move(this->width()*0.5-tmppix.width()*0.5,-50);//还没有砸下来
           winlabel->hide();
           //胜利图片显示
           winlabel->show();
           //胜利图片移动
           QPropertyAnimation *animation=new QPropertyAnimation(winlabel,"geometry");
           animation->setDuration(1000);
           //设置开始位置
           animation->setStartValue(QRect(winlabel->x(),winlabel->y(),winlabel->width(),winlabel->height()));
           //设置结束位置
           animation->setEndValue(QRect(winlabel->x(),winlabel->y()+114,winlabel->width(),winlabel->height()));
           //设置缓和曲线
           animation->setEasingCurve(QEasingCurve::OutBounce);
           //执行动画
           animation->start();
       }
    });
    //撤回
    //相当于下棋的反选
    connect(choice,&Choice::buttonCancel,[&](){
        if(!spinexist)return;
        this->gridBtn[spingridx][spingridy]->stopFlag(-1);//让数字还原为空
        spinexist=false;//停止转动，允许继续点击
        int r=spingridx,c=spingridy;
        cnt--;//wtf果然是SpinGridNum范围不对，改了半个小时
        qDebug()<<"r   "<<r<<"c    "<<c<<"cnt   "<<cnt<<"SpinGridNum"<<SpinGridNum;//显示一下哪里在旋转，和已经有填了多少了
        if(SpinGridNum!=-1)this->row[r][SpinGridNum-1]=0,this->col[c][SpinGridNum-1]=0,this->cell[r/3][c/3][SpinGridNum-1]=0;//记录结果,由于每次操作都是合法的，所以撤步之后对应的行列一定都没有了对应的数
//这里原来有数字才需要撤步
        //撤步之后要看看原来的配置是什么样的
        for(int i=0;i<9;i++){//现在也对了,i变成了行数，j是列数,是与config一一对应的,
            for(int j=0;j<9;j++){
                MyGrid *everyGrid=gridBtn[i][j];
                int GridNum=everyGrid->GridNum;
                qDebug()<<"i"<<i<<"  j"<<j<<"  "<<"GridNum"<<GridNum<<"starray"<<stArray[i][j]<<" "<<"row[i][GridNum]"<<row[i][GridNum]<<" col[j][GridNum]"<<col[j][GridNum]<<"cell[i/3][j/3][GridNum]"<<cell[i/3][j/3][GridNum];
            }
        }

    });//这里的SpinGridNum也是0~8

    //重新开始
    connect(choice,&Choice::buttonReDo,[&](){
       this->restart();
    });
    //显示答案
    connect(choice,&Choice::ShowAnswerButton,[&](){
        if(isWin)return;
        Solution *solution=new Solution(this);
        std::vector<std::vector<char>>v;
        for(int i=0;i<9;i++){
            std::vector<char>temp;
            for(int j=0;j<9;j++){
                if(levelIndex==17&&gridBtn[i][j]->GridNum!=-1){
                    temp.emplace_back(char(gridBtn[i][j]->GridNum+'0'));
                }
                else if(stArray[i][j]){
                    temp.emplace_back(char(gridBtn[i][j]->GridNum+'0'+1));
                }
                else temp.emplace_back('.');
            }
            v.emplace_back(temp);
        }
        this->myanswer=solution->solveSudoku(v);
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                qDebug()<<"i"<<i<<"j"<<j<<"myanswer[i][j]"<<myanswer[i][j];
            }
        }
    });

    //添加退出选项
    QMenuBar *bar=menuBar();
    setMenuBar(bar);
    QMenu *startMenu=bar->addMenu("选项");
    QAction *quitAction=startMenu->addAction("退出");
    //实现退出游戏

    connect(quitAction,&QAction::triggered,[=](){
        backtoLastS();
        this->close();
    });

    //实现重新添加选项栏
    QMenuBar *choicebar=menuBar();
    setMenuBar(choicebar);
    QAction *choicebarAction=startMenu->addAction("显示选项");
    //实现退出游戏
    connect(choicebarAction,&QAction::triggered,[=](){

        this->mychoice->show();
        this->mychoice->move(550,0);
        this->mychoice->setGeometry(this->x()+535,this->y()+280,choice->width(),choice->height());
        //操作界面退出事件
    });

    MypushButton *backBtn=new MypushButton(":/res/realBackButton.png");
    backBtn->setParent(this);
    backBtn->move(this->width()-backBtn->width(),this->height()*0.05-backBtn->height()*0.05);
    connect(backBtn,&QPushButton::clicked,[=](){
        if(isIndfs){
            indfsWantquit=true;
        };
        qDebug()<<"emit this->chooseSceneBack()";
        //主场景监听返回按钮
        backSound->play();//先播放返回按钮音效
        QTimer::singleShot(0,this,[=](){
            emit this->chooseSceneBack();
        });
    });
    //显示关卡数
    QLabel *label=new QLabel;
    label->setParent(this);
    QString str1=QString("第 %1 关").arg(this->levelIndex);
    if(levelIndex==17)str1="自定义";
    label->setText(str1);
    QFont qfont;
    qfont.setFamily("华文新魏");
    qfont.setPointSize(40);
    label->setFont(qfont);
    label->setGeometry(300,this->height()*0.15,240,70);

    dataConfig config;

    //初始化每个关卡的二维数组
    memset(row,0,sizeof row),memset(col,0,sizeof col),memset(cell,0,sizeof cell);
    for(int i=0;i<9;i++){//现在也对了,i变成了行数，j是列数,是与config一一对应的,
        for(int j=0;j<9;j++){
            int GridNum=config.mData[this->levelIndex][i][j];
            if(GridNum!=-1)GridNum--;
            this->gameArray[i][j]=GridNum;
            this->stArray[i][j]=GridNum==-1?0:1;//1表示系统给定的数字不可以修改
            if(GridNum!=-1){cnt++;
            row[i][GridNum]=1;//这里居然写成分号了，if后面应该有{}
            col[j][GridNum]=1;
            cell[i/3][j/3][GridNum]=1;
            }
            qDebug()<<"i"<<i<<"  j"<<j<<"  "<<"GridNum"<<GridNum<<"starray"<<stArray[i][j]<<" "<<"row[i][GridNum]"<<row[i][GridNum]<<" col[j][GridNum]"<<col[j][GridNum]<<"cell[i/3][j/3][GridNum]"<<cell[i/3][j/3][GridNum];
        }
    }



    //显示格子背景图案
    for(int i=0;i<9;i++){
        for(int j=0;j<9;j++){
//            QPixmap pix=QPixmap(":/res/BoardNode(1).png");
//            QLabel *label=new QLabel;
//            label->setGeometry(0,0,pix.width(),pix.height());
//            label->setPixmap(pix);
//            label->setParent(this);
//            label->move(57+i*50,200+j*50);

            //创建格子
            QString str;
            if(this->gameArray[i][j]==0)str=":/res/Num1.png";
            else if(this->gameArray[i][j]==1)str=":/res/Num2.png";
            else if(this->gameArray[i][j]==2)str=":/res/Num3.png";
            else if(this->gameArray[i][j]==3)str=":/res/Num4.png";
            else if(this->gameArray[i][j]==4)str=":/res/Num5.png";
            else if(this->gameArray[i][j]==5)str=":/res/Num6.png";
            else if(this->gameArray[i][j]==6)str=":/res/Num7.png";
            else if(this->gameArray[i][j]==7)str=":/res/Num8.png";
            else if(this->gameArray[i][j]==8)str=":/res/Num9.png";
            else str=":/res/Num0.png";
            MyGrid *grid=new MyGrid(str);
            grid->setParent(this);
            grid->move(50+j*50+12*(int)(j/3),204+i*50+12*(int)(i/3));//一定要反过来也只需要在这里反过来
            //写成/0了
            //给格子赋值
            grid->posX=i;
            grid->posy=j;
            grid->GridNum=gameArray[i][j];
            grid->flag=this->gameArray[i][j];//1是正面，2是反面
            //将格子放入便于维护
            gridBtn[i][j]=grid;
            //点击格子进行翻转
            connect(grid,&MyGrid::clicked,[=](){//本质上grid也是widget所以可以clicked
                qDebug()<<grid->posX<<" "<<grid->posy;//先看看点到的位置,应该是posx不是 posy
                //改好了，posX就是行数，posy就是列数
                //重新调取操作界面,不知道为什么搞不定
//                if(this->showChoice==0){
//                    showChoice=1;
//                    Choice *choice =new Choice(this);
//                    choice->show();
//                    choice->move(550,0);
//                    choice->setGeometry(this->x()+535,this->y()+280,choice->width(),choice->height());
//                }
                //放音乐
                //flipSound->play();
                //开始旋转
                if(isWin==false&&this->stArray[grid->posX][grid->posy]==0){//这个格子不能是原始的,胜利了不可以再点
                    if(this->spinexist==false){//如果原来没有在转的
                        grid->changeFlag();
                        this->spinexist=true,this->spingridx=grid->posX,this->spingridy=grid->posy,this->SpinGrid=grid,this->SpinGridNum=grid->GridNum;
                    }
                    else {
                        this->SpinGrid->stopFlag(this->SpinGridNum);
                        grid->changeFlag();
                        this->spinexist=true,this->spingridx=grid->posX,this->spingridy=grid->posy,this->SpinGrid=grid,this->SpinGridNum=grid->GridNum;
                    }
                }

            });
        }
    }
}
void PlayScene::paintEvent(QPaintEvent*){
    QPixmap BackGroundPic;
    BackGroundPic.load(":/res/MainWindowPic.png");
    BackGroundPic=BackGroundPic.scaled(BackGroundPic.width()*0.9,BackGroundPic.height()*0.9);
    QPainter painter(this);
    painter.drawPixmap(0,0,this->width(),this->height(),BackGroundPic);
};
void PlayScene::closeEvent(QCloseEvent *){
    indfsWantquit=true;
};
